package org.jeecg.modules.online.controller;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.modules.online.entity.ChartsData;
import org.jeecg.modules.online.entity.CommonConstants;
import org.jeecg.modules.online.entity.DiagramCombination;
import org.jeecg.modules.online.entity.DiagramCombinationDetail;
import org.jeecg.modules.online.entity.DiagramConfiguration;
import org.jeecg.modules.online.entity.DiagramFieldConfiguration;
import org.jeecg.modules.online.entity.GroupData;
import org.jeecg.modules.online.entity.TempletData;
import org.jeecg.modules.online.service.IDiagramCombinationDetailService;
import org.jeecg.modules.online.service.IDiagramCombinationService;
import org.jeecg.modules.online.service.IDiagramConfigurationService;
import org.jeecg.modules.online.service.IDiagramFieldConfigurationService;
import org.jeecg.modules.system.util.OnlineUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

/**
 * @Description: 图表配置
 */
@Slf4j
@Api(tags = "图表组合")
@RestController
@RequestMapping("/diagram/diagramCombination")
public class DiagramCombinationController extends JeecgController<DiagramCombination, IDiagramCombinationService>{

	@Autowired
	private IDiagramCombinationService diagramCombinationService;
	
	@Autowired
	private IDiagramCombinationDetailService diagramCombinationDetailService;
	
	@Autowired
	private IDiagramConfigurationService diagramConfigurationService;
	
	@Autowired
	private IDiagramFieldConfigurationService diagramFieldConfigurationService;
	
	/**
	 * 分页列表查询
	 *
	 * @param diagramCombination
	 * @param pageNo
	 * @param pageSize
	 * @param req
	 * @return
	 */
	@AutoLog(value = "图表组合配置-分页列表查询")
	@ApiOperation(value = "图表组合配置-分页列表查询", notes = "图表组合配置-分页列表查询")
	@GetMapping(value = "/list")
	public Result<?> queryPageList(DiagramCombination diagramCombination,
			@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
			@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) {
		QueryWrapper<DiagramCombination> queryWrapper = QueryGenerator.initQueryWrapper(diagramCombination, req.getParameterMap());
		Page<DiagramCombination> page = new Page<DiagramCombination>(pageNo, pageSize);
		IPage<DiagramCombination> pageList = diagramCombinationService.page(page, queryWrapper);
		List<DiagramCombination> records = pageList.getRecords();
		if (records != null && !records.isEmpty()) {
			for (DiagramCombination record : records) {
				QueryWrapper<DiagramCombinationDetail> qw = new QueryWrapper<DiagramCombinationDetail>();
				qw.eq("GRAPHREPORT_TEMPLET_ID", record.getId()).orderByAsc("ORDER_NUM");
				List<DiagramCombinationDetail> diagramCombinationDetails = this.diagramCombinationDetailService
						.list(qw);
				record.setDiagramCombinationDetails(diagramCombinationDetails);
			}
		}
		return Result.ok(pageList);
	}
	
	/**
	 * 添加
	 *
	 * @param diagramCombination
	 * @return
	 */
	@AutoLog(value = "图表组合配置-添加")
	@ApiOperation(value = "图表组合配置-添加", notes = "图表组合配置-添加")
	@PostMapping(value = "/add")
	public Result<?> add(@RequestBody DiagramCombination diagramCombination) {
		// 校验code是否重复
		Result<?> result = this.duplicateCheck(diagramCombination.getTempletCode());
		if (result != null) {
			return result;
		}
		// 保存主表/子表信息
		try {
			this.diagramCombinationService.add(diagramCombination);
		} catch (Exception e) {
			e.printStackTrace();
			log.error(CommonConstants.MSG_ERROR_OPERATE, e);
			return Result.error(e.getMessage());
		}
		// 渲染客户端
		return Result.ok(CommonConstants.MSG_SUCCESS_ADD);
	}
	
	/**
	 * 编辑
	 *
	 * @param diagramCombination
	 * @return
	 */
	@AutoLog(value = "图表组合配置-编辑")
	@ApiOperation(value = "图表组合配置-编辑", notes = "图表组合配置-编辑")
	@PutMapping(value = "/edit")
	public Result<?> edit(@RequestBody DiagramCombination diagramCombination) {
		try {
			this.diagramCombinationService.edit(diagramCombination);
		} catch (Exception e) {
			e.printStackTrace();
			log.error(CommonConstants.MSG_ERROR_OPERATE, e);
			return Result.error(e.getMessage());
		}
		return Result.ok(CommonConstants.MSG_SUCCESS_EDIT);
	}

	/**
	 * 通过id删除
	 *
	 * @param id
	 * @return
	 */
	@AutoLog(value = "图表组合配置-通过id删除")
	@ApiOperation(value = "图表组合配置-通过id删除", notes = "图表组合配置-通过id删除")
	@DeleteMapping(value = "/delete")
	public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
		try {
			this.diagramCombinationService.deleteById(id);
		} catch (Exception e) {
			e.printStackTrace();
			log.error(CommonConstants.MSG_ERROR_OPERATE, e);
			return Result.error(e.getMessage());
		}
		return Result.ok(CommonConstants.MSG_SUCCESS_DELTET);
	}

	/**
	 * 批量删除
	 *
	 * @param ids
	 * @return
	 */
	@AutoLog(value = "图表组合配置-批量删除")
	@ApiOperation(value = "图表组合配置-批量删除", notes = "图表组合配置-批量删除")
	@DeleteMapping(value = "/deleteBatch")
	public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
		try {
			this.diagramCombinationService.deleteBatch(ids);
		} catch (Exception e) {
			e.printStackTrace();
			log.error(CommonConstants.MSG_ERROR_OPERATE, e);
			return Result.error(e.getMessage());
		}
		return Result.ok(CommonConstants.MSG_SUCCESS_DELTET_BATCH);
	}
	
	/**
	 * 通过id查询
	 *
	 * @param id
	 * @return
	 */
	@AutoLog(value = "图表组合配置-通过id查询")
	@ApiOperation(value = "图表组合配置-通过id查询", notes = "图表组合配置-通过id查询")
	@GetMapping(value = "/queryById")
	public Result<?> queryById(@RequestParam(name = "id", required = true) String id) {
		DiagramCombination diagramCombination = diagramCombinationService.getById(id);
		if (diagramCombination == null) {
			return Result.error(CommonConstants.MSG_ERROR_NO_DATA_FOUND + "[ " + id + " ]");
		}
		return Result.ok(diagramCombination);
	}

	/**
	 * 导出excel
	 *
	 * @param request
	 * @param diagramConfiguration
	 */
	@RequestMapping(value = "/exportXls")
	public ModelAndView exportXls(HttpServletRequest request, DiagramCombination diagramCombination) {
		return super.exportXls(request, diagramCombination, DiagramCombination.class, "图表组合配置");
	}

	/**
	 * 通过excel导入数据
	 *
	 * @param request
	 * @param response
	 * @return
	 */

	@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
	public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
		return super.importExcel(request, response, DiagramCombination.class);
	}
	
	//@AutoLog(value = "图表组合配置-获取图表数据")
	//@ApiOperation(value="图表组合配置-获取图表数据", notes="图表组合配置-获取图表数据")
	@RequestMapping(value = "/getTempletData", method = RequestMethod.GET)
	@Transactional(readOnly = true)
	public Result<?> getTempletData(@RequestParam(name = "templetCode", required = true) String templetCode) throws CloneNotSupportedException {
		// 查询主表信息
		QueryWrapper<DiagramCombination> diagramCombinationQueryWrapper = new QueryWrapper<>();
		diagramCombinationQueryWrapper.eq("templet_code", templetCode);
		DiagramCombination diagramCombination = this.diagramCombinationService
				.getOne(diagramCombinationQueryWrapper);
		if (diagramCombination == null) {
			return Result.error(CommonConstants.MSG_ERROR_NO_DATA_FOUND + "[ " + templetCode + " ]");
		}
		
		TempletData<DiagramCombination,Object, DiagramConfiguration, DiagramFieldConfiguration> templetData = new TempletData<>();
		List<GroupData<ChartsData<Object, DiagramConfiguration, DiagramFieldConfiguration>>> templetDataGroup = new ArrayList<>();
		templetData.setGroups(templetDataGroup);
		templetData.setTemplet(diagramCombination);
		QueryWrapper<DiagramCombinationDetail> qw = new QueryWrapper<DiagramCombinationDetail>();
		qw.eq("GRAPHREPORT_TEMPLET_ID", diagramCombination.getId()).orderByAsc("GROUP_NUM","ORDER_NUM");
		List<DiagramCombinationDetail> diagramCombinationDetails = this.diagramCombinationDetailService
				.list(qw);
		
		Integer currentGroupNum = null;
		GroupData<ChartsData<Object, DiagramConfiguration, DiagramFieldConfiguration>> currentGroupData = new GroupData<>();;
		
		if(CollectionUtils.isNotEmpty(diagramCombinationDetails)){
			for(DiagramCombinationDetail diagramCombinationDetail : diagramCombinationDetails){
				
				if(currentGroupNum != diagramCombinationDetail.getGroupNum()){
					currentGroupNum = diagramCombinationDetail.getGroupNum();
					if(CollectionUtils.isNotEmpty(currentGroupData.getCharts())){
						templetData.getGroups().add(currentGroupData);
						currentGroupData = new GroupData<>();
					}else{
						currentGroupData = new GroupData<>();
					}
					
					//初始化分组数据
					currentGroupData.setGroupNum(currentGroupNum);
					currentGroupData.setGroupStyle(diagramCombinationDetail.getGroupStyle());
					currentGroupData.setGroupTxt(diagramCombinationDetail.getGroupTxt());
					currentGroupData.setTempletGrid(diagramCombinationDetail.getTempletGrid());
					currentGroupData.setCharts( new ArrayList<ChartsData<Object, DiagramConfiguration, DiagramFieldConfiguration>>());
					
				}
				
				QueryWrapper<DiagramConfiguration> dcQw = new QueryWrapper<>();
				dcQw.eq("code", diagramCombinationDetail.getGraphreportCode());
				DiagramConfiguration diagramConfiguration = (DiagramConfiguration) diagramConfigurationService
						.getOne(dcQw).clone();
				if (diagramConfiguration == null) {
					return Result.error(CommonConstants.MSG_ERROR_NO_DATA_FOUND + "[ " + diagramCombinationDetail.getGraphreportCode() + " ]");
				}
				
				if(StringUtils.isNotBlank(diagramCombinationDetail.getGraphreportType())){
					diagramConfiguration.setGraphType(diagramCombinationDetail.getGraphreportType());
				}

				// 根据sql查询数据
				List dataList = Collections.emptyList();
				if (CommonConstants.DATA_TYPE_SQL.equals(diagramConfiguration.getDataType())) {
					dataList = this.diagramConfigurationService.selectBySql(diagramConfiguration.getCgrSql());
				}

				// 获取子表信息
				QueryWrapper<DiagramFieldConfiguration> diagramFieldConfigurationQueryWrapper = new QueryWrapper<>();
				diagramFieldConfigurationQueryWrapper.eq("DIAGRAM_CODE", diagramCombinationDetail.getGraphreportCode());
				List<DiagramFieldConfiguration> diagramFieldConfigurationList = this.diagramFieldConfigurationService
						.list(diagramFieldConfigurationQueryWrapper);
				Map<String, Expression> expressions = new HashMap<>();
				Map<String, String> aggregates = new HashMap<>();
				
				Map<Object,Map<String, Object>> aggregateDataMap = new HashMap<Object,Map<String, Object>>();
				
				String xField = diagramConfiguration.getXaxisField();
				String[] yFields = diagramConfiguration.getYaxisField().split(",");
				
				for(DiagramFieldConfiguration dfc : diagramFieldConfigurationList){
					if(StringUtils.isNotEmpty(dfc.getFunc())){
						String expression = dfc.getFunc();
						Expression compiledExp = AviatorEvaluator.compile(expression);
						expressions.put(dfc.getFieldName(), compiledExp);
					}
		/*			if(StringUtils.isNotEmpty(dfc.getAggregateType())){
						aggregates.put(dfc.getFieldName(), dfc.getAggregateType());
					}*/
					if(ArrayUtils.contains(yFields, dfc.getFieldName())){
						aggregates.put(dfc.getFieldName(), dfc.getAggregateType());
					}
				}
				if(expressions.size()>0 || diagramConfiguration.getAggregate()){
					for(Object data : dataList){
						if(data instanceof Map){
							for(Entry<String, Expression> entry : expressions.entrySet()){
								Map<String,Object> env = new HashMap<String,Object>();
								env.putAll((Map<String,Object>) data);
								((Map<String,Object>) data).put(entry.getKey(), entry.getValue().execute(env));
							}
							if(diagramConfiguration.getAggregate()){
								Object xValue = ((Map) data).get(xField);
								if(aggregateDataMap.get(xValue) == null){
									Map<String, Object> aggregateData = new HashMap<>();
									aggregateData.put(xField, xValue);
									for(Entry<String, String> yField : aggregates.entrySet()){
										aggregateData.put(yField.getKey(),BigDecimal.ZERO);
									}
									aggregateDataMap.put(xValue, aggregateData);
								}
								
								Map<String, Object> aggregateData = aggregateDataMap.get(xValue);
								for(Entry<String, String> yField : aggregates.entrySet()){
									aggregateData.put(yField.getKey(), OnlineUtil.calculation(aggregateData.get(yField.getKey()), ((Map) data).get(yField.getKey()), yField.getValue()));
								}
								aggregateDataMap.put(xValue, aggregateData);
							}
						}
					}
				}
				Map<String,Collection> result = new HashMap<String, Collection>();
				result.put("data", dataList);
				result.put("aggregate", aggregateDataMap.values());
				// 封装数据
				ChartsData<Object, DiagramConfiguration, DiagramFieldConfiguration> chartsData = new ChartsData<>();
				chartsData.setData(result);
				chartsData.setDictOptions(null);
				chartsData.setParam(diagramCombinationDetail);
				chartsData.setHead(diagramConfiguration);
				chartsData.setItems(diagramFieldConfigurationList);
				currentGroupData.getCharts().add(chartsData);
			}
			if(CollectionUtils.isNotEmpty(currentGroupData.getCharts())){
				templetData.getGroups().add(currentGroupData);
			}
		}
		
		return Result.ok(templetData);
	}
	
	/**
	 * 远程code重复校验
	 * 
	 * @param code
	 * @return
	 */
	@AutoLog(value = "图表组合配置-code重复校验")
	@ApiOperation(value = "图表组合配置-code重复校验", notes = "图表组合配置-code重复校验")
	@RequestMapping(value = "/codeCheck", method = RequestMethod.GET)
	public Result<?> codeCheck(@RequestParam(name = "templetCode", required = true) String templetCode) {
		Result<?> result = this.duplicateCheck(templetCode);
		if (result != null) {
			return result;
		}
		return Result.ok();
	}
	
	/**
	 * code重复校验
	 * 
	 * @param code
	 * @return
	 */
	private Result<?> duplicateCheck(String templetCode) {
		QueryWrapper<DiagramCombination> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("templet_code", templetCode);
		List<DiagramCombination> diagramCombinationList = this.diagramCombinationService.list(queryWrapper);
		if (diagramCombinationList != null && !diagramCombinationList.isEmpty()) {
			return Result.error(CommonConstants.MSG_EXIST + "[ " + templetCode + " ]");
		}
		return null;
	}
}
